#include <iomanip>
#include <iostream>
#include <iostream>
#include <string>

#include "Random.h"
#include "Player.h"

using namespace std;

/**
 * Print the Classes for the Player to choose
 * @param std::vector<Class*> classes - list of classes
 * @return void
 */
void Player::printClasses(std::vector<Class*> classes)
{
	system("cls");
	cout << endl << "======PROFESSIONS=====================" << endl;
	cout << "=========" << endl;
	cout << "====" << endl;
	for (unsigned int i = 0; i < classes.size(); ++i)
	{
		cout << "| " << i + 1 << ") ";
		classes[i]->printName();
		cout << setw(10) << setfill(' ') << endl;
		cout << "Description: " ;
		classes[i]->printDesc();
		cout << endl;
		cout << "______________________________________" << endl;
	}
}


/**
 * Process to generate a character. Name, Stats, Class and equipment are set here
 * @param std::vector<Class*> classes - list of Classes to refer to
 * @param std::vector<Item*> items - list of Items to refer to
 * @param int iXPforLvlOne - Max XP for Level 1 Player
 * @return void
 */
void Player::generate(std::vector<Class*> classes, std::vector<Item*> items, int iXPforLvlOne)
{
	m_iLevel = 1;
	m_iXP = 0;
	m_iMaxXP = iXPforLvlOne;
	newName();
	rollStats();
	selectClass(classes);
	setInitialEquipment(items);
	cout << "A new hero named " << m_strName << " enters the World of Legends" << endl;
	cout << "All equipment is in the backpack. Do not forget to equip your weapons and armor." << endl;
	system("pause");

}


/**
 * Set Attributes of a Player
 * @param int iStr
 * @param int iRfx
 * @param int iInt
 * @param int Psy
 * @param int iCha
 * @return void
 */
void Player::setAttributes(int iStr, int iRfx, int iInt, int Psy, int iCha)
{
	m_iStrength = iStr;
	m_iReflexes = iRfx;
	m_iIntelligence = iInt;
	m_iPsychic = Psy;
	m_iCharisma = iCha;
}


/**
 * List of referenced classes. Name of the class to create.
 * @param std::vector<Class*> classes
 * @param string strClassName
 * @return void
 */
void Player::setClass(std::vector<Class*> classes, string strClassName)
{
	for (unsigned int i = 0; i < classes.size(); ++i)
	{
		if ((classes[i]->getName()).compare(strClassName) == 0)
		{
			if (m_class == 0)
			{
				m_class = new Class;
				*(m_class) = *(classes[i]);
			}
		}
	}
}


/**
 * Show all available Professions and ask the Player to choose one.
 * The class is then associated to the Player
 * @param std::vector<Class*> classes
 * @return void
 */
void Player::selectClass(std::vector<Class*> classes)
{
	int				bHappy = false;
	unsigned int	iSelection = 0;

	while (!bHappy)
	{
		system("cls");
		printClasses(classes);
		cout << "Choice [1-" << classes.size() << "] :" << endl ;
		cin >> iSelection;
		if ((iSelection > 0) && 
			(iSelection <= classes.size()))
		{
			--iSelection;
			if (classes[iSelection]->checkRequirements(m_iStrength,
													   m_iReflexes,
													   m_iIntelligence,
													   m_iPsychic,
													   m_iCharisma))
			{
				system("cls");
				cout << "Congratulations! You have selected the noble profession of " << classes[iSelection]->getName() << "." << endl;
				m_class = new Class;
				*(m_class) = *(classes[iSelection]);
				applyClass();
				statAdjustments();
				m_iHP = m_iMaxHP;
				m_iMP = m_iMaxMP;
				bHappy = true;
			}
			else
			{
				cout << "Your Character is not fit for this Profession." << endl;
				system("pause");
			}
		}
		else
		{
			cout << "Please enter a correct choice." << endl;
			system("pause");
		}
	}
}


/**
 * Apply the specificity of the class to the Player
 * @param void
 * @return void
 */
void Player::applyClass()
{
	if (m_class != 0)
	{
		setInitHP(m_class->getInitHP());
		setInitMP(m_class->getInitMP());
		setPhysicalCombatAttr(m_class->getInitPhysAttack(), m_class->getInitPhysDefense());
		setMagicalCombatAttr(m_class->getInitMagAttack(), m_class->getInitMagDefense());
		setEvasion(m_class->getInitEvasion());
		setDiscretion(m_class->getInitStealth(), m_class->getInitPerception());
		setGold(m_class->getInitGold());
	}
}


/**
 * Ask the Player for a new name for his/her Character
 * @param void
 * @return void
 */
void Player::newName()
{
	system("cls");
	cin.sync();
	cout << "Enter your name: ";
	getline(cin, m_strName);
}


/**
 * Rolls the dice for the Attributes of the Player
 * and ask if the Player is happy with them
 * @param void
 * @return void
 */
void Player::rollStats()
{
	int bHappy = false;
	char selection = 'n';

	while (!bHappy)
	{
		system("cls");
		cout << endl;
		cout << "Rolling the dices for your base stats (3-18):" << endl<< endl;
		m_iStrength = Random(3, 18);
		m_iReflexes = Random(3, 18);
		m_iIntelligence = Random(3, 18);
		m_iPsychic = Random(3, 18);
		m_iCharisma = Random(3, 18);
		cout << "  /= = = = = = = = = = = = = \\" << endl;
		cout << "  |      CHARACTERISTICS     |" << endl;
		cout << " /= = = = = = = = = = = = = = \\" << endl;
		cout << "||                           ||" << endl;
		cout << "|| Strength: " << setw(2) << m_iStrength << setw(16) << setfill(' ') << "||" << endl;
		cout << "|| Reflexes: " << setw(2) << m_iReflexes << setw(16) << setfill(' ') << "||" << endl;
		cout << "|| Intelligence: " << setw(2) << m_iIntelligence << setw(12) << setfill(' ') << "||" << endl;
		cout << "|| Psychic: " << setw(2) << m_iPsychic << setw(17) << setfill(' ') << "||" << endl;
		cout << "|| Charisma: " << setw(2) << m_iCharisma << setw(16) << setfill(' ') << "||" << endl;
		cout << "||                           ||" << endl;
		cout << " \\= = = = = = = = = = = = = =/" << endl;
		cout << "  \\= = = = = = = = = = = = =/" << endl << endl;
		cout << "Are you happy with the result? (Y/n)";
		cin >> selection;
		if ((selection == 'y') || (selection == 'Y'))
			bHappy = true;
	}
}


/**
 * Adjust Player characteristics according to different attributes
 * @param void
 * @return void
 */
void Player::statAdjustments()
{
	statAdjustmentsForStr();
	statAdjustmentsForRfx();
	statAdjustmentsForInt();
	statAdjustmentsForPsy();
	statAdjustmentsForCha();
}


/**
 * Adjust Player characteristics according to strength
 * @param void
 * @return void
 */
void Player::statAdjustmentsForStr()
{
	if (m_iStrength <= 5)
	{
		m_iPhysicalAttack -= 2;
		m_iPhysicalDefense -= 1;
	}
	if ((m_iStrength >= 6) && (m_iStrength <= 8))
	{
		m_iPhysicalAttack -= 1;
	}
	if ((m_iStrength >= 13) && (m_iStrength <= 15))
	{
		m_iPhysicalAttack += 1;
	}
	if (m_iStrength >= 16)
	{
		m_iPhysicalAttack += 2;
		m_iPhysicalDefense += 1;
	}
}


/**
 * Adjust Player characteristics according to reflexes
 * @param void
 * @return void
 */
void Player::statAdjustmentsForRfx()
{
	if (m_iReflexes <= 5)
	{
		m_iPhysicalAttack -= 1;
		m_iPhysicalDefense -= 2;
		m_iEvasion -= 2;
		m_iStealth -= 1;
	}
	if ((m_iReflexes >= 6) && (m_iReflexes <= 8))
	{
		m_iPhysicalDefense -= 1;
		m_iEvasion -= 1;
	}
	if ((m_iReflexes >= 13) && (m_iReflexes <= 15))
	{
		m_iPhysicalDefense += 1;
		m_iEvasion += 1;
	}
	if (m_iReflexes >= 16)
	{
		m_iPhysicalAttack += 1;
		m_iPhysicalDefense += 2;
		m_iEvasion += 2;
		m_iStealth += 1;
	}
}


/**
 * Adjust Player characteristics according to intelligence
 * @param void
 * @return void
 */
void Player::statAdjustmentsForInt()
{
	if (m_iIntelligence <= 5)
	{
		m_iPhysicalAttack -= 1;
		m_iPhysicalDefense -= 1;
		m_iMagicalAttack -= 1;
		m_iMagicalDefense -= 1;
	}

	if (m_iIntelligence >= 16)
	{
		m_iPhysicalAttack += 1;
		m_iPhysicalDefense += 1;
		m_iMagicalAttack += 1;
		m_iMagicalDefense += 1;
	}
}


/**
 * Adjust Player characteristics according to psychic
 * @param void
 * @return void
 */
void Player::statAdjustmentsForPsy()
{
	if (m_iPsychic <= 5)
	{
		m_iPerception -= 1;
		m_iMagicalAttack -= 1;
		m_iMagicalDefense -= 2;
	}
	if ((m_iPsychic >= 6) && (m_iPsychic <= 8))
	{
		m_iMagicalDefense -= 1;
	}
	if ((m_iPsychic >= 13) && (m_iPsychic <= 15))
	{
		m_iMagicalDefense += 1;
	}
	if (m_iPsychic >= 16)
	{
		m_iPerception += 1;
		m_iMagicalAttack += 2;
		m_iMagicalDefense += 2;
	}
}


/**
 * Adjust Player characteristics according to charisma
 * @param void
 * @return void
 */
void Player::statAdjustmentsForCha()
{
	if (m_iCharisma <= 5)
	{
	}
	if ((m_iCharisma >= 6) && (m_iCharisma <= 8))
	{
	}
	if ((m_iCharisma >= 13) && (m_iCharisma <= 15))
	{
	}
	if (m_iCharisma >= 16)
	{
	}
}


